iT邦幫忙

2024 iThome 鐵人賽

DAY 9
0
Software Development

一起看無間道學EdgeDB系列 第 9

[Day09] - EdgeQL牛刀小試

  • 分享至 

  • xImage
  •  

考慮schema如下:

type User {
    required name: str;
    multi followers: User;
}

type Article {
    required title: str;
    required author: User;
}

本日的學習目標是希望透過前面幾天的說明,大家能獨自完成下面這四道練習:

  • Q1:建立三個User objectJeffTomCathy,其name property分別為「"Jeff"」、「"Tom"」及「"Cathy"」。

  • Q2:將每個User objectmulti followers link設定為除了自己以外的兩個User object

  • Q3:將Cathy自每個User objectmulti followers link中移除。

  • Q4:建立三個Article object,其title property分別為「"title1"」、「"title2"」、及「"title3"」,其author link為三個User object中隨機選取一位。

以下我們提供兩個方法作為參考答案。方法1是基礎的操作,而方法2借鑒方法1的寫法,並搭配for-loop使得query更加結構化。

方法1:基礎思維

1.1:insert User object

首先建立三個User object,並指定其name property

insert User {name:= "Jeff"};
insert User {name:= "Tom"};
insert User {name:="Cathy"};

此時三個User object成功建立。

select User {name};
{
    default::User {name: 'Jeff'}, 
    default::User {name: 'Tom'}, 
    default::User {name: 'Cathy'}
}

1.2 update User object - 加入新User objectmulti followers link

接著update三個User object內的multi followers link

update User filter .name="Jeff" 
set {
    multi followers:= (select User filter .name in {"Tom", "Cathy"})
};

update User filter .name="Tom" 
set {
    multi followers:= (select User filter .name in {"Jeff", "Cathy"})
};


update User filter .name="Cathy" 
set {
    multi followers:= (select User filter .name in {"Jeff", "Tom"})
};

但我們卻發現multi followers link並沒有更新,聰明的您看出來問題在哪邊了嗎?

select User {**};
{
  default::User {
      id: f789868a-4fd2-11ef-8734-db28a46e9f9c, 
      name: 'Jeff', 
      followers: {}
  },
  default::User {
      id: f78ca9c8-4fd2-11ef-8734-53dcbb5a15d8, 
      name: 'Tom', 
      followers: {}
  },
  default::User {
      id: f78ef002-4fd2-11ef-8734-eb9d204119a7, 
      name: 'Cathy', 
      followers: {}
  },
}

沒錯,就是關於之前於[Day05]提過的detached,實務上這是一個非常容易犯錯的地方,需要多加小心。

正確的query可以寫為:

update User filter .name="Jeff" 
set {
    followers:= (select detached User filter .name in {"Tom", "Cathy"})
};

update User filter .name="Tom" 
set {
    followers:= (select detached User filter .name in {"Jeff", "Cathy"})
};


update User filter .name="Cathy" 
set {
    followers:= (select detached User filter .name in {"Jeff", "Tom"})
};

又或者搭配with寫為:

with jeff:= (select User filter .name="Jeff"),
     followers:= (select User filter .name in {"Tom", "Cathy"})
update jeff
set {
    followers:= followers
};

with tom:= (select User filter .name="tom"),
     followers:= (select User filter .name in {"Jeff", "Cathy"})
update tom
set {
    followers:= followers
};

with cathy:= (select User filter .name="Cathy"),
     followers:= (select User filter .name in {"Jeff", "Tom"})
update cathy
set {
    followers:= followers
};

1.3 update User object - 自multi followers link中移除Cathy

這邊利用-=來移除Cathy

with jeff:= (select User filter .name="Jeff"),
     cathy:= (select User filter .name="Cathy")
update jeff
set {
    followers-= cathy
};

with tom:= (select User filter .name="Tom"),
     cathy:= (select User filter .name="Cathy")
update tom
set {
    followers-= cathy
};

如果不習慣這樣的寫法,也可以寫成:

with jeff:= (select User filter .name="Jeff"),
     cathy:= (select User filter .name="Cathy")
update jeff
set {
    followers:= .followers except cathy
};

with tom:= (select User filter .name="Tom"),
     cathy:= (select User filter .name="Cathy")
update tom
set {
    followers:= .followers except cathy
};

留意這邊使用的是:=:=代表將.followers except cathy這個set operation的結果指定給multi followers link

1.4 insert Article object

最後建立三個Article object,並指定其name property

insert Article {
    title:= "title1",
    author:= (select User order by random() limit 1)
};

insert Article {
    title:= "title2",
    author:= (select User order by random() limit 1)
};

insert Article {
    title:= "title3",
    author:= (select User order by random() limit 1)
};

這邊我們使用了random()來隨機產生一個0.0 <= x < 1.0間的浮點數,並搭配order by來產生一個隨機的排序,最後再使用了limit 1來選擇第一個元素。

此時三個Article object成功建立。

select Article {title, author: {name} };
{
  default::Article {title: 'title1', author: default::User {name: 'Cathy'}},
  default::Article {title: 'title2', author: default::User {name: 'Cathy'}},
  default::Article {title: 'title3', author: default::User {name: 'Tom'}},
}

方法2:結構化思維

2.1:insert User object

我們將names集合為一個EdgeDBSet,就可以於迴圈中指定User objectname property

with names:= {"Jeff", "Tom", "Cathy"}
for name in names 
union (insert User {name:= name});

2.2:update User object - 加入新User objectmulti followers link

此處我們靈活運用set operation中的except來選取除自己外的User object

with names:= {"Jeff", "Tom", "Cathy"}
for name in names 
union (
    with user:= (select User filter .name=name)
    update user
    set {
        followers:= (select User except user)
    }
);

2.3:update User object - 自multi followers link中移除Cathy

這邊我們使用select User.name來選取所有User objectname property所形成的EdgeDBSet並使用except來排除「"Cathy"」這個str

with names:= (select User.name except {"Cathy"}),
     cathy:= (select User filter .name="Cathy")
for name in names 
union (
    with user:= (select User filter .name=name)
    update user 
    set {
        followers-= cathy
    }
);

這種使用.來選擇object typepropertylink十分方便,但初學時容易忘記,這邊特別提醒大家。

2.4:insert Article object

此處我們利用range_unpack在每個迴圈中取得1, 2, 3,並使用<str>i將其轉為str型別後,搭配++與「"title"」合併。

for i in range_unpack(range(1, 4))
union (
    insert Article {
        title:= "title" ++ <str>i,
        author:= (select User order by random() limit 1)
    }
);

上一篇
[Day08] - 介紹tuple、range及multirange
下一篇
[Day10] - 初始schema:人
系列文
一起看無間道學EdgeDB30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言